home *** CD-ROM | disk | FTP | other *** search
/ CD/PC Actual 31 / PC Actual CD 31.iso / dists / SRC / SLIBEXEC.AA / SLIBEXEC / libexec / ftpd / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-13  |  49.9 KB  |  2,305 lines

  1. /*
  2.  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #if 0
  35. #ifndef lint
  36. static char copyright[] =
  37. "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
  38.     The Regents of the University of California.  All rights reserved.\n";
  39. #endif /* not lint */
  40. #endif
  41.  
  42. #ifndef lint
  43. #if 0
  44. static char sccsid[] = "@(#)ftpd.c    8.4 (Berkeley) 4/16/94";
  45. #endif
  46. static const char rcsid[] =
  47.     "$Id: ftpd.c,v 1.52 1998/10/13 20:42:01 des Exp $";
  48. #endif /* not lint */
  49.  
  50. /*
  51.  * FTP server.
  52.  */
  53. #include <sys/param.h>
  54. #include <sys/stat.h>
  55. #include <sys/ioctl.h>
  56. #include <sys/socket.h>
  57. #include <sys/wait.h>
  58. #include <sys/mman.h>
  59.  
  60. #include <netinet/in.h>
  61. #include <netinet/in_systm.h>
  62. #include <netinet/ip.h>
  63. #include <netinet/tcp.h>
  64.  
  65. #define    FTP_NAMES
  66. #include <arpa/ftp.h>
  67. #include <arpa/inet.h>
  68. #include <arpa/telnet.h>
  69.  
  70. #include <ctype.h>
  71. #include <dirent.h>
  72. #include <err.h>
  73. #include <errno.h>
  74. #include <fcntl.h>
  75. #include <glob.h>
  76. #include <limits.h>
  77. #include <netdb.h>
  78. #include <pwd.h>
  79. #include <grp.h>
  80. #include <setjmp.h>
  81. #include <signal.h>
  82. #include <stdio.h>
  83. #include <stdlib.h>
  84. #include <string.h>
  85. #include <syslog.h>
  86. #include <time.h>
  87. #include <unistd.h>
  88. #include <libutil.h>
  89. #ifdef    LOGIN_CAP
  90. #include <login_cap.h>
  91. #endif
  92.  
  93. #ifdef    SKEY
  94. #include <skey.h>
  95. #endif
  96.  
  97. #include "pathnames.h"
  98. #include "extern.h"
  99.  
  100. #if __STDC__
  101. #include <stdarg.h>
  102. #else
  103. #include <varargs.h>
  104. #endif
  105.  
  106. #ifdef    INTERNAL_LS
  107. static char version[] = "Version 6.00LS";
  108. #undef main
  109. #else
  110. static char version[] = "Version 6.00";
  111. #endif
  112.  
  113. extern    off_t restart_point;
  114. extern    char cbuf[];
  115.  
  116. struct    sockaddr_in server_addr;
  117. struct    sockaddr_in ctrl_addr;
  118. struct    sockaddr_in data_source;
  119. struct    sockaddr_in data_dest;
  120. struct    sockaddr_in his_addr;
  121. struct    sockaddr_in pasv_addr;
  122.  
  123. int    daemon_mode;
  124. int    data;
  125. jmp_buf    errcatch, urgcatch;
  126. int    logged_in;
  127. struct    passwd *pw;
  128. int    debug;
  129. int    timeout = 900;    /* timeout after 15 minutes of inactivity */
  130. int    maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
  131. int    logging;
  132. int    restricted_data_ports = 1;
  133. int    paranoid = 1;      /* be extra careful about security */
  134. int    anon_only = 0;    /* Only anonymous ftp allowed */
  135. int    guest;
  136. int    dochroot;
  137. int    stats;
  138. int    statfd = -1;
  139. int    type;
  140. int    form;
  141. int    stru;            /* avoid C keyword */
  142. int    mode;
  143. int    usedefault = 1;        /* for data transfers */
  144. int    pdata = -1;        /* for passive mode */
  145. sig_atomic_t transflag;
  146. off_t    file_size;
  147. off_t    byte_count;
  148. #if !defined(CMASK) || CMASK == 0
  149. #undef CMASK
  150. #define CMASK 027
  151. #endif
  152. int    defumask = CMASK;        /* default umask value */
  153. char    tmpline[7];
  154. char    *hostname;
  155. #ifdef VIRTUAL_HOSTING
  156. char    *ftpuser;
  157.  
  158. static struct ftphost {
  159.     struct ftphost    *next;
  160.     struct in_addr    hostaddr;
  161.     char        *hostname;
  162.     char        *anonuser;
  163.     char        *statfile;
  164.     char        *welcome;
  165.     char        *loginmsg;
  166. } *thishost, *firsthost;
  167.  
  168. #endif
  169. char    remotehost[MAXHOSTNAMELEN];
  170. char    *ident = NULL;
  171.  
  172. static char ttyline[20];
  173. char    *tty = ttyline;        /* for klogin */
  174.  
  175. #ifdef KERBEROS
  176. int     klogin __P((struct passwd *, char *, char *, char *));
  177. #endif
  178.  
  179. struct    in_addr bind_address;
  180. char    *pid_file = NULL;
  181.  
  182. #if defined(KERBEROS)
  183. int    notickets = 1;
  184. int    noticketsdontcomplain = 1;
  185. char    *krbtkfile_env = NULL;
  186. #endif
  187.  
  188. /*
  189.  * Timeout intervals for retrying connections
  190.  * to hosts that don't accept PORT cmds.  This
  191.  * is a kludge, but given the problems with TCP...
  192.  */
  193. #define    SWAITMAX    90    /* wait at most 90 seconds */
  194. #define    SWAITINT    5    /* interval between retries */
  195.  
  196. int    swaitmax = SWAITMAX;
  197. int    swaitint = SWAITINT;
  198.  
  199. #ifdef SETPROCTITLE
  200. #ifdef OLD_SETPROCTITLE
  201. char    **Argv = NULL;        /* pointer to argument vector */
  202. char    *LastArgv = NULL;    /* end of argv */
  203. #endif /* OLD_SETPROCTITLE */
  204. char    proctitle[LINE_MAX];    /* initial part of title */
  205. #endif /* SETPROCTITLE */
  206.  
  207. #ifdef SKEY
  208. int    pwok = 0;
  209. char    addr_string[20];    /* XXX */
  210. #endif
  211.  
  212. #define LOGCMD(cmd, file) \
  213.     if (logging > 1) \
  214.         syslog(LOG_INFO,"%s %s%s", cmd, \
  215.         *(file) == '/' ? "" : curdir(), file);
  216. #define LOGCMD2(cmd, file1, file2) \
  217.      if (logging > 1) \
  218.         syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
  219.         *(file1) == '/' ? "" : curdir(), file1, \
  220.         *(file2) == '/' ? "" : curdir(), file2);
  221. #define LOGBYTES(cmd, file, cnt) \
  222.     if (logging > 1) { \
  223.         if (cnt == (off_t)-1) \
  224.             syslog(LOG_INFO,"%s %s%s", cmd, \
  225.             *(file) == '/' ? "" : curdir(), file); \
  226.         else \
  227.             syslog(LOG_INFO, "%s %s%s = %qd bytes", \
  228.             cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
  229.     }
  230.  
  231. #ifdef VIRTUAL_HOSTING
  232. static void     inithosts __P((void));
  233. static void    selecthost __P((struct in_addr *));
  234. #endif
  235. static void     ack __P((char *));
  236. static void     myoob __P((int));
  237. static int     checkuser __P((char *, char *, int));
  238. static FILE    *dataconn __P((char *, off_t, char *));
  239. static void     dolog __P((struct sockaddr_in *));
  240. static char    *curdir __P((void));
  241. static void     end_login __P((void));
  242. static FILE    *getdatasock __P((char *));
  243. static char    *gunique __P((char *));
  244. static void     lostconn __P((int));
  245. static int     receive_data __P((FILE *, FILE *));
  246. static void     send_data __P((FILE *, FILE *, off_t, off_t, int));
  247. static struct passwd *
  248.          sgetpwnam __P((char *));
  249. static char    *sgetsave __P((char *));
  250. static void     reapchild __P((int));
  251. static void      logxfer __P((char *, long, long));
  252.  
  253. static char *
  254. curdir()
  255. {
  256.     static char path[MAXPATHLEN+1+1];    /* path + '/' + '\0' */
  257.  
  258.     if (getcwd(path, sizeof(path)-2) == NULL)
  259.         return ("");
  260.     if (path[1] != '\0')        /* special case for root dir. */
  261.         strcat(path, "/");
  262.     /* For guest account, skip / since it's chrooted */
  263.     return (guest ? path+1 : path);
  264. }
  265.  
  266. int
  267. main(argc, argv, envp)
  268.     int argc;
  269.     char *argv[];
  270.     char **envp;
  271. {
  272.     int addrlen, ch, on = 1, tos;
  273.     char *cp, line[LINE_MAX];
  274.     FILE *fd;
  275.  
  276.     tzset();        /* in case no timezone database in ~ftp */
  277.  
  278. #ifdef OLD_SETPROCTITLE
  279.     /*
  280.      *  Save start and extent of argv for setproctitle.
  281.      */
  282.     Argv = argv;
  283.     while (*envp)
  284.         envp++;
  285.     LastArgv = envp[-1] + strlen(envp[-1]);
  286. #endif /* OLD_SETPROCTITLE */
  287.  
  288.  
  289.     bind_address.s_addr = htonl(INADDR_ANY);
  290.     while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
  291.         switch (ch) {
  292.         case 'D':
  293.             daemon_mode++;
  294.             break;
  295.  
  296.         case 'd':
  297.             debug++;
  298.             break;
  299.  
  300.         case 'l':
  301.             logging++;    /* > 1 == extra logging */
  302.             break;
  303.  
  304.         case 'R':
  305.             paranoid = 0;
  306.             break;
  307.  
  308.         case 'S':
  309.             stats++;
  310.             break;
  311.  
  312.         case 'T':
  313.             maxtimeout = atoi(optarg);
  314.             if (timeout > maxtimeout)
  315.                 timeout = maxtimeout;
  316.             break;
  317.  
  318.         case 't':
  319.             timeout = atoi(optarg);
  320.             if (maxtimeout < timeout)
  321.                 maxtimeout = timeout;
  322.             break;
  323.  
  324.         case 'U':
  325.             restricted_data_ports = 0;
  326.             break;
  327.  
  328.         case 'a':
  329.             if (!inet_aton(optarg, &bind_address))
  330.                 errx(1, "invalid address for -a");
  331.             break;
  332.  
  333.         case 'p':
  334.             pid_file = optarg;
  335.             break;
  336.  
  337.         case 'u':
  338.             {
  339.             long val = 0;
  340.  
  341.             val = strtol(optarg, &optarg, 8);
  342.             if (*optarg != '\0' || val < 0)
  343.                 warnx("bad value for -u");
  344.             else
  345.                 defumask = val;
  346.             break;
  347.             }
  348.         case 'A':
  349.             anon_only = 1;
  350.             break;
  351.  
  352.         case 'v':
  353.             debug = 1;
  354.             break;
  355.  
  356.         default:
  357.             warnx("unknown flag -%c ignored", optopt);
  358.             break;
  359.         }
  360.     }
  361.  
  362. #ifdef VIRTUAL_HOSTING
  363.     inithosts();
  364. #endif
  365.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  366.  
  367.     /*
  368.      * LOG_NDELAY sets up the logging connection immediately,
  369.      * necessary for anonymous ftp's that chroot and can't do it later.
  370.      */
  371.     openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
  372.  
  373.     if (daemon_mode) {
  374.         int ctl_sock, fd;
  375.         struct servent *sv;
  376.  
  377.         /*
  378.          * Detach from parent.
  379.          */
  380.         if (daemon(1, 1) < 0) {
  381.             syslog(LOG_ERR, "failed to become a daemon");
  382.             exit(1);
  383.         }
  384.         (void) signal(SIGCHLD, reapchild);
  385.         /*
  386.          * Get port number for ftp/tcp.
  387.          */
  388.         sv = getservbyname("ftp", "tcp");
  389.         if (sv == NULL) {
  390.             syslog(LOG_ERR, "getservbyname for ftp failed");
  391.             exit(1);
  392.         }
  393.         /*
  394.          * Open a socket, bind it to the FTP port, and start
  395.          * listening.
  396.          */
  397.         ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
  398.         if (ctl_sock < 0) {
  399.             syslog(LOG_ERR, "control socket: %m");
  400.             exit(1);
  401.         }
  402.         if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
  403.             (char *)&on, sizeof(on)) < 0)
  404.             syslog(LOG_ERR, "control setsockopt: %m");;
  405.         server_addr.sin_family = AF_INET;
  406.         server_addr.sin_addr = bind_address;
  407.         server_addr.sin_port = sv->s_port;
  408.         if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
  409.             syslog(LOG_ERR, "control bind: %m");
  410.             exit(1);
  411.         }
  412.         if (listen(ctl_sock, 32) < 0) {
  413.             syslog(LOG_ERR, "control listen: %m");
  414.             exit(1);
  415.         }
  416.         /*
  417.          * Atomically write process ID
  418.          */
  419.         if (pid_file)
  420.         {   
  421.             int fd;
  422.             char buf[20];
  423.  
  424.             fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC
  425.                 | O_NONBLOCK | O_EXLOCK, 0644);
  426.             if (fd < 0)
  427.                 if (errno == EAGAIN)
  428.                     errx(1, "%s: file locked", pid_file);
  429.                 else
  430.                     err(1, "%s", pid_file);
  431.             snprintf(buf, sizeof(buf),
  432.                 "%lu\n", (unsigned long) getpid());
  433.             if (write(fd, buf, strlen(buf)) < 0)
  434.                 err(1, "%s: write", pid_file);
  435.             /* Leave the pid file open and locked */
  436.         }
  437.         /*
  438.          * Loop forever accepting connection requests and forking off
  439.          * children to handle them.
  440.          */
  441.         while (1) {
  442.             addrlen = sizeof(his_addr);
  443.             fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
  444.             if (fork() == 0) {
  445.                 /* child */
  446.                 (void) dup2(fd, 0);
  447.                 (void) dup2(fd, 1);
  448.                 close(ctl_sock);
  449.                 break;
  450.             }
  451.             close(fd);
  452.         }
  453.     } else {
  454.         addrlen = sizeof(his_addr);
  455.         if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  456.             syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
  457.             exit(1);
  458.         }
  459.     }
  460.  
  461.     (void) signal(SIGCHLD, SIG_IGN);
  462.     (void) signal(SIGPIPE, lostconn);
  463.     if (signal(SIGURG, myoob) == SIG_ERR)
  464.         syslog(LOG_ERR, "signal: %m");
  465.  
  466. #ifdef SKEY
  467.     strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
  468. #endif
  469.     addrlen = sizeof(ctrl_addr);
  470.     if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
  471.         syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
  472.         exit(1);
  473.     }
  474. #ifdef VIRTUAL_HOSTING
  475.     /* select our identity from virtual host table */
  476.     selecthost(&ctrl_addr.sin_addr);
  477. #endif
  478. #ifdef IP_TOS
  479.     tos = IPTOS_LOWDELAY;
  480.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  481.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  482. #endif
  483.     /*
  484.      * Disable Nagle on the control channel so that we don't have to wait
  485.      * for peer's ACK before issuing our next reply.
  486.      */
  487.     if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
  488.         syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
  489.  
  490.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  491.  
  492.     /* set this here so klogin can use it... */
  493.     (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
  494.  
  495.     /* Try to handle urgent data inline */
  496. #ifdef SO_OOBINLINE
  497.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
  498.         syslog(LOG_ERR, "setsockopt: %m");
  499. #endif
  500.  
  501. #ifdef    F_SETOWN
  502.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  503.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  504. #endif
  505.     dolog(&his_addr);
  506.     /*
  507.      * Set up default state
  508.      */
  509.     data = -1;
  510.     type = TYPE_A;
  511.     form = FORM_N;
  512.     stru = STRU_F;
  513.     mode = MODE_S;
  514.     tmpline[0] = '\0';
  515.  
  516.     /* If logins are disabled, print out the message. */
  517.     if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
  518.         while (fgets(line, sizeof(line), fd) != NULL) {
  519.             if ((cp = strchr(line, '\n')) != NULL)
  520.                 *cp = '\0';
  521.             lreply(530, "%s", line);
  522.         }
  523.         (void) fflush(stdout);
  524.         (void) fclose(fd);
  525.         reply(530, "System not available.");
  526.         exit(0);
  527.     }
  528. #ifdef VIRTUAL_HOSTING
  529.     if ((fd = fopen(thishost->welcome, "r")) != NULL) {
  530. #else
  531.     if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
  532. #endif
  533.         while (fgets(line, sizeof(line), fd) != NULL) {
  534.             if ((cp = strchr(line, '\n')) != NULL)
  535.                 *cp = '\0';
  536.             lreply(220, "%s", line);
  537.         }
  538.         (void) fflush(stdout);
  539.         (void) fclose(fd);
  540.         /* reply(220,) must follow */
  541.     }
  542. #ifndef VIRTUAL_HOSTING
  543.     if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL)
  544.         fatal("Ran out of memory.");
  545.     (void) gethostname(hostname, MAXHOSTNAMELEN);
  546. #endif
  547.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  548.     (void) setjmp(errcatch);
  549.     for (;;)
  550.         (void) yyparse();
  551.     /* NOTREACHED */
  552. }
  553.  
  554. static void
  555. lostconn(signo)
  556.     int signo;
  557. {
  558.  
  559.     if (debug)
  560.         syslog(LOG_DEBUG, "lost connection");
  561.     dologout(1);
  562. }
  563.  
  564. #ifdef VIRTUAL_HOSTING
  565. /*
  566.  * read in virtual host tables (if they exist)
  567.  */
  568.  
  569. static void
  570. inithosts()
  571. {
  572.     FILE *fp;
  573.     char *cp;
  574.     struct hostent *hp;
  575.     struct ftphost *hrp, *lhrp;
  576.     char line[1024];
  577.  
  578.     /*
  579.      * Fill in the default host information
  580.      */
  581.     if (gethostname(line, sizeof(line)) < 0)
  582.         line[0] = '\0';
  583.     if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
  584.         (hrp->hostname = strdup(line)) == NULL)
  585.         fatal("Ran out of memory.");
  586.     memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
  587.     if ((hp = gethostbyname(hrp->hostname)) != NULL)
  588.         (void) memcpy(&hrp->hostaddr,
  589.                   hp->h_addr_list[0],
  590.                   sizeof(hrp->hostaddr));
  591.     hrp->statfile = _PATH_FTPDSTATFILE;
  592.     hrp->welcome  = _PATH_FTPWELCOME;
  593.     hrp->loginmsg = _PATH_FTPLOGINMESG;
  594.     hrp->anonuser = "ftp";
  595.     hrp->next = NULL;
  596.     thishost = firsthost = lhrp = hrp;
  597.     if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
  598.         while (fgets(line, sizeof(line), fp) != NULL) {
  599.             int    i;
  600.  
  601.             if ((cp = strchr(line, '\n')) == NULL) {
  602.                 /* ignore long lines */
  603.                 while (fgets(line, sizeof(line), fp) != NULL &&
  604.                     strchr(line, '\n') == NULL)
  605.                     ;
  606.                 continue;
  607.             }
  608.             *cp = '\0';
  609.             cp = strtok(line, " \t");
  610.             /* skip comments and empty lines */
  611.             if (cp == NULL || line[0] == '#')
  612.                 continue;
  613.             /* first, try a standard gethostbyname() */
  614.             if ((hp = gethostbyname(cp)) == NULL)
  615.                 continue;
  616.             for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
  617.                 if (memcmp(&hrp->hostaddr,
  618.                        hp->h_addr_list[0],
  619.                        sizeof(hrp->hostaddr)) == 0)
  620.                     break;
  621.             }
  622.             if (hrp == NULL) {
  623.                 if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
  624.                     continue;
  625.                 /* defaults */
  626.                 hrp->statfile = _PATH_FTPDSTATFILE;
  627.                 hrp->welcome  = _PATH_FTPWELCOME;
  628.                 hrp->loginmsg = _PATH_FTPLOGINMESG;
  629.                 hrp->anonuser = "ftp";
  630.                 hrp->next     = NULL;
  631.                 lhrp->next = hrp;
  632.                 lhrp = hrp;
  633.             }
  634.             (void) memcpy(&hrp->hostaddr,
  635.                       hp->h_addr_list[0],
  636.                       sizeof(hrp->hostaddr));
  637.             /*
  638.              * determine hostname to use.
  639.              * force defined name if it is a valid alias
  640.              * otherwise fallback to primary hostname
  641.              */
  642.             if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
  643.                         sizeof(hrp->hostaddr),
  644.                         AF_INET)) != NULL) {
  645.                 if (strcmp(cp, hp->h_name) != 0) {
  646.                     if (hp->h_aliases == NULL)
  647.                         cp = hp->h_name;
  648.                     else {
  649.                         i = 0;
  650.                         while (hp->h_aliases[i] &&
  651.                                strcmp(cp, hp->h_aliases[i]) != 0)
  652.                             ++i;
  653.                         if (hp->h_aliases[i] == NULL)
  654.                             cp = hp->h_name;
  655.                     }
  656.                 }
  657.             }
  658.             hrp->hostname = strdup(cp);
  659.             /* ok, now we now peel off the rest */
  660.             i = 0;
  661.             while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
  662.                 if (*cp != '-' && (cp = strdup(cp)) != NULL) {
  663.                     switch (i) {
  664.                     case 0:    /* anon user permissions */
  665.                         hrp->anonuser = cp;
  666.                         break;
  667.                     case 1: /* statistics file */
  668.                         hrp->statfile = cp;
  669.                         break;
  670.                     case 2: /* welcome message */
  671.                         hrp->welcome  = cp;
  672.                         break;
  673.                     case 3: /* login message */
  674.                         hrp->loginmsg = cp;
  675.                         break;
  676.                     }
  677.                 }
  678.                 ++i;
  679.             }
  680.         }
  681.         (void) fclose(fp);
  682.     }
  683. }
  684.  
  685. static void
  686. selecthost(a)
  687.     struct in_addr *a;
  688. {
  689.     struct ftphost    *hrp;
  690.  
  691.     hrp = thishost = firsthost;    /* default */
  692.     while (hrp != NULL) {
  693.         if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
  694.             thishost = hrp;
  695.             break;
  696.         }
  697.         hrp = hrp->next;
  698.     }
  699.     /* setup static variables as appropriate */
  700.     hostname = thishost->hostname;
  701.     ftpuser = thishost->anonuser;
  702. }
  703. #endif
  704.  
  705. /*
  706.  * Helper function for sgetpwnam().
  707.  */
  708. static char *
  709. sgetsave(s)
  710.     char *s;
  711. {
  712.     char *new = malloc((unsigned) strlen(s) + 1);
  713.  
  714.     if (new == NULL) {
  715.         perror_reply(421, "Local resource failure: malloc");
  716.         dologout(1);
  717.         /* NOTREACHED */
  718.     }
  719.     (void) strcpy(new, s);
  720.     return (new);
  721. }
  722.  
  723. /*
  724.  * Save the result of a getpwnam.  Used for USER command, since
  725.  * the data returned must not be clobbered by any other command
  726.  * (e.g., globbing).
  727.  */
  728. static struct passwd *
  729. sgetpwnam(name)
  730.     char *name;
  731. {
  732.     static struct passwd save;
  733.     struct passwd *p;
  734.  
  735.     if ((p = getpwnam(name)) == NULL)
  736.         return (p);
  737.     if (save.pw_name) {
  738.         free(save.pw_name);
  739.         free(save.pw_passwd);
  740.         free(save.pw_gecos);
  741.         free(save.pw_dir);
  742.         free(save.pw_shell);
  743.     }
  744.     save = *p;
  745.     save.pw_name = sgetsave(p->pw_name);
  746.     save.pw_passwd = sgetsave(p->pw_passwd);
  747.     save.pw_gecos = sgetsave(p->pw_gecos);
  748.     save.pw_dir = sgetsave(p->pw_dir);
  749.     save.pw_shell = sgetsave(p->pw_shell);
  750.     return (&save);
  751. }
  752.  
  753. static int login_attempts;    /* number of failed login attempts */
  754. static int askpasswd;        /* had user command, ask for passwd */
  755. static char curname[10];    /* current USER name */
  756.  
  757. /*
  758.  * USER command.
  759.  * Sets global passwd pointer pw if named account exists and is acceptable;
  760.  * sets askpasswd if a PASS command is expected.  If logged in previously,
  761.  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
  762.  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
  763.  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
  764.  * requesting login privileges.  Disallow anyone who does not have a standard
  765.  * shell as returned by getusershell().  Disallow anyone mentioned in the file
  766.  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
  767.  */
  768. void
  769. user(name)
  770.     char *name;
  771. {
  772.     char *cp, *shell;
  773.  
  774.     if (logged_in) {
  775.         if (guest) {
  776.             reply(530, "Can't change user from guest login.");
  777.             return;
  778.         } else if (dochroot) {
  779.             reply(530, "Can't change user from chroot user.");
  780.             return;
  781.         }
  782.         end_login();
  783.     }
  784.  
  785.     guest = 0;
  786.     if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
  787.         if (checkuser(_PATH_FTPUSERS, "ftp", 0) ||
  788.             checkuser(_PATH_FTPUSERS, "anonymous", 0))
  789.             reply(530, "User %s access denied.", name);
  790. #ifdef VIRTUAL_HOSTING
  791.         else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
  792. #else
  793.         else if ((pw = sgetpwnam("ftp")) != NULL) {
  794. #endif
  795.             guest = 1;
  796.             askpasswd = 1;
  797.             reply(331,
  798.             "Guest login ok, send your email address as password.");
  799.         } else
  800.             reply(530, "User %s unknown.", name);
  801.         if (!askpasswd && logging)
  802.             syslog(LOG_NOTICE,
  803.                 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
  804.         return;
  805.     }
  806.     if (anon_only != 0) {
  807.         reply(530, "Sorry, only anonymous ftp allowed.");
  808.         return;
  809.     }
  810.         
  811.     if ((pw = sgetpwnam(name))) {
  812.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  813.             shell = _PATH_BSHELL;
  814.         while ((cp = getusershell()) != NULL)
  815.             if (strcmp(cp, shell) == 0)
  816.                 break;
  817.         endusershell();
  818.  
  819.         if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) {
  820.             reply(530, "User %s access denied.", name);
  821.             if (logging)
  822.                 syslog(LOG_NOTICE,
  823.                     "FTP LOGIN REFUSED FROM %s, %s",
  824.                     remotehost, name);
  825.             pw = (struct passwd *) NULL;
  826.             return;
  827.         }
  828.     }
  829.     if (logging)
  830.         strncpy(curname, name, sizeof(curname)-1);
  831. #ifdef SKEY
  832.     pwok = skeyaccess(name, NULL, remotehost, addr_string);
  833.     reply(331, "%s", skey_challenge(name, pw, pwok));
  834. #else
  835.     reply(331, "Password required for %s.", name);
  836. #endif
  837.     askpasswd = 1;
  838.     /*
  839.      * Delay before reading passwd after first failed
  840.      * attempt to slow down passwd-guessing programs.
  841.      */
  842.     if (login_attempts)
  843.         sleep((unsigned) login_attempts);
  844. }
  845.  
  846. /*
  847.  * Check if a user is in the file "fname"
  848.  */
  849. static int
  850. checkuser(fname, name, pwset)
  851.     char *fname;
  852.     char *name;
  853.     int pwset;
  854. {
  855.     FILE *fd;
  856.     int found = 0;
  857.     char *p, line[BUFSIZ];
  858.  
  859.     if ((fd = fopen(fname, "r")) != NULL) {
  860.         while (!found && fgets(line, sizeof(line), fd) != NULL)
  861.             if ((p = strchr(line, '\n')) != NULL) {
  862.                 *p = '\0';
  863.                 if (line[0] == '#')
  864.                     continue;
  865.                 /*
  866.                  * if first chr is '@', check group membership
  867.                  */
  868.                 if (line[0] == '@') {
  869.                     int i = 0;
  870.                     struct group *grp;
  871.  
  872.                     if ((grp = getgrnam(line+1)) == NULL)
  873.                         continue;
  874.                     /*
  875.                      * Check user's default group
  876.                      */
  877.                     if (pwset && grp->gr_gid == pw->pw_gid)
  878.                         found = 1;
  879.                     /*
  880.                      * Check supplementary groups
  881.                      */
  882.                     while (!found && grp->gr_mem[i])
  883.                         found = strcmp(name,
  884.                             grp->gr_mem[i++])
  885.                             == 0;
  886.                 }
  887.                 /*
  888.                  * Otherwise, just check for username match
  889.                  */
  890.                 else
  891.                     found = strcmp(line, name) == 0;
  892.             }
  893.         (void) fclose(fd);
  894.     }
  895.     return (found);
  896. }
  897.  
  898. /*
  899.  * Terminate login as previous user, if any, resetting state;
  900.  * used when USER command is given or login fails.
  901.  */
  902. static void
  903. end_login()
  904. {
  905.  
  906.     (void) seteuid((uid_t)0);
  907.     if (logged_in)
  908.         ftpd_logwtmp(ttyline, "", "");
  909.     pw = NULL;
  910. #ifdef    LOGIN_CAP
  911.     setusercontext(NULL, getpwuid(0), (uid_t)0,
  912.                LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
  913. #endif
  914.     logged_in = 0;
  915.     guest = 0;
  916.     dochroot = 0;
  917. }
  918.  
  919. void
  920. pass(passwd)
  921.     char *passwd;
  922. {
  923.     int rval;
  924.     FILE *fd;
  925. #ifdef    LOGIN_CAP
  926.     login_cap_t *lc = NULL;
  927. #endif
  928.  
  929.     if (logged_in || askpasswd == 0) {
  930.         reply(503, "Login with USER first.");
  931.         return;
  932.     }
  933.     askpasswd = 0;
  934.     if (!guest) {        /* "ftp" is only account allowed no password */
  935.         if (pw == NULL) {
  936.             rval = 1;    /* failure below */
  937.             goto skip;
  938.         }
  939. #if defined(KERBEROS)
  940.         rval = klogin(pw, "", hostname, passwd);
  941.         if (rval == 0)
  942.             goto skip;
  943. #endif
  944. #ifdef SKEY
  945.         rval = strcmp(skey_crypt(passwd, pw->pw_passwd, pw, pwok),
  946.                   pw->pw_passwd);
  947.         pwok = 0;
  948. #else
  949.         rval = strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd);
  950. #endif
  951.         /* The strcmp does not catch null passwords! */
  952.         if (*pw->pw_passwd == '\0' ||
  953.             (pw->pw_expire && time(NULL) >= pw->pw_expire))
  954.             rval = 1;    /* failure */
  955. skip:
  956.         /*
  957.          * If rval == 1, the user failed the authentication check
  958.          * above.  If rval == 0, either Kerberos or local authentication
  959.          * succeeded.
  960.          */
  961.         if (rval) {
  962.             reply(530, "Login incorrect.");
  963.             if (logging)
  964.                 syslog(LOG_NOTICE,
  965.                     "FTP LOGIN FAILED FROM %s, %s",
  966.                     remotehost, curname);
  967.             pw = NULL;
  968.             if (login_attempts++ >= 5) {
  969.                 syslog(LOG_NOTICE,
  970.                     "repeated login failures from %s",
  971.                     remotehost);
  972.                 exit(0);
  973.             }
  974.             return;
  975.         }
  976.     }
  977.     login_attempts = 0;        /* this time successful */
  978.     if (setegid((gid_t)pw->pw_gid) < 0) {
  979.         reply(550, "Can't set gid.");
  980.         return;
  981.     }
  982.     /* May be overridden by login.conf */
  983.     (void) umask(defumask);
  984. #ifdef    LOGIN_CAP
  985.     if ((lc = login_getpwclass(pw)) != NULL) {
  986.         char    remote_ip[MAXHOSTNAMELEN];
  987.  
  988.         strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
  989.             sizeof(remote_ip) - 1);
  990.         remote_ip[sizeof(remote_ip) - 1] = 0;
  991.         if (!auth_hostok(lc, remotehost, remote_ip)) {
  992.             syslog(LOG_INFO|LOG_AUTH,
  993.                 "FTP LOGIN FAILED (HOST) as %s: permission denied.",
  994.                 pw->pw_name);
  995.             reply(530, "Permission denied.\n");
  996.             pw = NULL;
  997.             return;
  998.         }
  999.         if (!auth_timeok(lc, time(NULL))) {
  1000.             reply(530, "Login not available right now.\n");
  1001.             pw = NULL;
  1002.             return;
  1003.         }
  1004.     }
  1005.     setusercontext(lc, pw, (uid_t)0,
  1006.         LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
  1007.         LOGIN_SETRESOURCES|LOGIN_SETUMASK);
  1008. #else
  1009.     setlogin(pw->pw_name);
  1010.     (void) initgroups(pw->pw_name, pw->pw_gid);
  1011. #endif
  1012.  
  1013.     /* open wtmp before chroot */
  1014.     ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
  1015.     logged_in = 1;
  1016.  
  1017.     if (guest && stats && statfd < 0)
  1018. #ifdef VIRTUAL_HOSTING
  1019.         if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
  1020. #else
  1021.         if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
  1022. #endif
  1023.             stats = 0;
  1024.  
  1025.     dochroot =
  1026. #ifdef    LOGIN_CAP    /* Allow login.conf configuration as well */
  1027.         login_getcapbool(lc, "ftp-chroot", 0) ||
  1028. #endif
  1029.         checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
  1030.     if (guest) {
  1031.         /*
  1032.          * We MUST do a chdir() after the chroot. Otherwise
  1033.          * the old current directory will be accessible as "."
  1034.          * outside the new root!
  1035.          */
  1036.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1037.             reply(550, "Can't set guest privileges.");
  1038.             goto bad;
  1039.         }
  1040.     } else if (dochroot) {
  1041.         if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1042.             reply(550, "Can't change root.");
  1043.             goto bad;
  1044.         }
  1045.     } else if (chdir(pw->pw_dir) < 0) {
  1046.         if (chdir("/") < 0) {
  1047.             reply(530, "User %s: can't change directory to %s.",
  1048.                 pw->pw_name, pw->pw_dir);
  1049.             goto bad;
  1050.         } else
  1051.             lreply(230, "No directory! Logging in with home=/");
  1052.     }
  1053.     if (seteuid((uid_t)pw->pw_uid) < 0) {
  1054.         reply(550, "Can't set uid.");
  1055.         goto bad;
  1056.     }
  1057.  
  1058.     /*
  1059.      * Display a login message, if it exists.
  1060.      * N.B. reply(230,) must follow the message.
  1061.      */
  1062. #ifdef VIRTUAL_HOSTING
  1063.     if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
  1064. #else
  1065.     if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
  1066. #endif
  1067.         char *cp, line[LINE_MAX];
  1068.  
  1069.         while (fgets(line, sizeof(line), fd) != NULL) {
  1070.             if ((cp = strchr(line, '\n')) != NULL)
  1071.                 *cp = '\0';
  1072.             lreply(230, "%s", line);
  1073.         }
  1074.         (void) fflush(stdout);
  1075.         (void) fclose(fd);
  1076.     }
  1077.     if (guest) {
  1078.         if (ident != NULL)
  1079.             free(ident);
  1080.         ident = strdup(passwd);
  1081.         if (ident == NULL)
  1082.             fatal("Ran out of memory.");
  1083.  
  1084.         reply(230, "Guest login ok, access restrictions apply.");
  1085. #ifdef SETPROCTITLE
  1086. #ifdef VIRTUAL_HOSTING
  1087.         if (thishost != firsthost)
  1088.             snprintf(proctitle, sizeof(proctitle),
  1089.                  "%s: anonymous(%s)/%.*s", remotehost, hostname,
  1090.                  sizeof(proctitle) - sizeof(remotehost) -
  1091.                  sizeof(": anonymous/"), passwd);
  1092.         else
  1093. #endif
  1094.             snprintf(proctitle, sizeof(proctitle),
  1095.                  "%s: anonymous/%.*s", remotehost,
  1096.                  sizeof(proctitle) - sizeof(remotehost) -
  1097.                  sizeof(": anonymous/"), passwd);
  1098.         setproctitle("%s", proctitle);
  1099. #endif /* SETPROCTITLE */
  1100.         if (logging)
  1101.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
  1102.                 remotehost, passwd);
  1103.     } else {
  1104.         if (dochroot)
  1105.         reply(230, "User %s logged in, access restrictions apply.", 
  1106.             pw->pw_name);
  1107.         else
  1108.         reply(230, "User %s logged in.", pw->pw_name);
  1109.  
  1110. #ifdef SETPROCTITLE
  1111.         snprintf(proctitle, sizeof(proctitle),
  1112.              "%s: %s", remotehost, pw->pw_name);
  1113.         setproctitle("%s", proctitle);
  1114. #endif /* SETPROCTITLE */
  1115.         if (logging)
  1116.             syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
  1117.                 remotehost, pw->pw_name);
  1118.     }
  1119. #ifdef    LOGIN_CAP
  1120.     login_close(lc);
  1121. #endif
  1122.     return;
  1123. bad:
  1124.     /* Forget all about it... */
  1125. #ifdef    LOGIN_CAP
  1126.     login_close(lc);
  1127. #endif
  1128.     end_login();
  1129. }
  1130.  
  1131. void
  1132. retrieve(cmd, name)
  1133.     char *cmd, *name;
  1134. {
  1135.     FILE *fin, *dout;
  1136.     struct stat st;
  1137.     int (*closefunc) __P((FILE *));
  1138.     time_t start;
  1139.  
  1140.     if (cmd == 0) {
  1141.         fin = fopen(name, "r"), closefunc = fclose;
  1142.         st.st_size = 0;
  1143.     } else {
  1144.         char line[BUFSIZ];
  1145.  
  1146.         (void) snprintf(line, sizeof(line), cmd, name), name = line;
  1147.         fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
  1148.         st.st_size = -1;
  1149.         st.st_blksize = BUFSIZ;
  1150.     }
  1151.     if (fin == NULL) {
  1152.         if (errno != 0) {
  1153.             perror_reply(550, name);
  1154.             if (cmd == 0) {
  1155.                 LOGCMD("get", name);
  1156.             }
  1157.         }
  1158.         return;
  1159.     }
  1160.     byte_count = -1;
  1161.     if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
  1162.         reply(550, "%s: not a plain file.", name);
  1163.         goto done;
  1164.     }
  1165.     if (restart_point) {
  1166.         if (type == TYPE_A) {
  1167.             off_t i, n;
  1168.             int c;
  1169.  
  1170.             n = restart_point;
  1171.             i = 0;
  1172.             while (i++ < n) {
  1173.                 if ((c=getc(fin)) == EOF) {
  1174.                     perror_reply(550, name);
  1175.                     goto done;
  1176.                 }
  1177.                 if (c == '\n')
  1178.                     i++;
  1179.             }
  1180.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  1181.             perror_reply(550, name);
  1182.             goto done;
  1183.         }
  1184.     }
  1185.     dout = dataconn(name, st.st_size, "w");
  1186.     if (dout == NULL)
  1187.         goto done;
  1188.     time(&start);
  1189.     send_data(fin, dout, st.st_blksize, st.st_size,
  1190.           restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
  1191.     if (cmd == 0 && guest && stats)
  1192.         logxfer(name, st.st_size, start);
  1193.     (void) fclose(dout);
  1194.     data = -1;
  1195.     pdata = -1;
  1196. done:
  1197.     if (cmd == 0)
  1198.         LOGBYTES("get", name, byte_count);
  1199.     (*closefunc)(fin);
  1200. }
  1201.  
  1202. void
  1203. store(name, mode, unique)
  1204.     char *name, *mode;
  1205.     int unique;
  1206. {
  1207.     FILE *fout, *din;
  1208.     struct stat st;
  1209.     int (*closefunc) __P((FILE *));
  1210.  
  1211.     if ((unique || guest) && stat(name, &st) == 0 &&
  1212.         (name = gunique(name)) == NULL) {
  1213.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  1214.         return;
  1215.     }
  1216.  
  1217.     if (restart_point)
  1218.         mode = "r+";
  1219.     fout = fopen(name, mode);
  1220.     closefunc = fclose;
  1221.     if (fout == NULL) {
  1222.         perror_reply(553, name);
  1223.         LOGCMD(*mode == 'w' ? "put" : "append", name);
  1224.         return;
  1225.     }
  1226.     byte_count = -1;
  1227.     if (restart_point) {
  1228.         if (type == TYPE_A) {
  1229.             off_t i, n;
  1230.             int c;
  1231.  
  1232.             n = restart_point;
  1233.             i = 0;
  1234.             while (i++ < n) {
  1235.                 if ((c=getc(fout)) == EOF) {
  1236.                     perror_reply(550, name);
  1237.                     goto done;
  1238.                 }
  1239.                 if (c == '\n')
  1240.                     i++;
  1241.             }
  1242.             /*
  1243.              * We must do this seek to "current" position
  1244.              * because we are changing from reading to
  1245.              * writing.
  1246.              */
  1247.             if (fseek(fout, 0L, L_INCR) < 0) {
  1248.                 perror_reply(550, name);
  1249.                 goto done;
  1250.             }
  1251.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  1252.             perror_reply(550, name);
  1253.             goto done;
  1254.         }
  1255.     }
  1256.     din = dataconn(name, (off_t)-1, "r");
  1257.     if (din == NULL)
  1258.         goto done;
  1259.     if (receive_data(din, fout) == 0) {
  1260.         if (unique)
  1261.             reply(226, "Transfer complete (unique file name:%s).",
  1262.                 name);
  1263.         else
  1264.             reply(226, "Transfer complete.");
  1265.     }
  1266.     (void) fclose(din);
  1267.     data = -1;
  1268.     pdata = -1;
  1269. done:
  1270.     LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
  1271.     (*closefunc)(fout);
  1272. }
  1273.  
  1274. static FILE *
  1275. getdatasock(mode)
  1276.     char *mode;
  1277. {
  1278.     int on = 1, s, t, tries;
  1279.  
  1280.     if (data >= 0)
  1281.         return (fdopen(data, mode));
  1282.     (void) seteuid((uid_t)0);
  1283.     s = socket(AF_INET, SOCK_STREAM, 0);
  1284.     if (s < 0)
  1285.         goto bad;
  1286.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  1287.         (char *) &on, sizeof(on)) < 0)
  1288.         goto bad;
  1289.     /* anchor socket to avoid multi-homing problems */
  1290.     data_source.sin_len = sizeof(struct sockaddr_in);
  1291.     data_source.sin_family = AF_INET;
  1292.     data_source.sin_addr = ctrl_addr.sin_addr;
  1293.     for (tries = 1; ; tries++) {
  1294.         if (bind(s, (struct sockaddr *)&data_source,
  1295.             sizeof(data_source)) >= 0)
  1296.             break;
  1297.         if (errno != EADDRINUSE || tries > 10)
  1298.             goto bad;
  1299.         sleep(tries);
  1300.     }
  1301.     (void) seteuid((uid_t)pw->pw_uid);
  1302. #ifdef IP_TOS
  1303.     on = IPTOS_THROUGHPUT;
  1304.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  1305.         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  1306. #endif
  1307. #ifdef TCP_NOPUSH
  1308.     /*
  1309.      * Turn off push flag to keep sender TCP from sending short packets
  1310.      * at the boundaries of each write().  Should probably do a SO_SNDBUF
  1311.      * to set the send buffer size as well, but that may not be desirable
  1312.      * in heavy-load situations.
  1313.      */
  1314.     on = 1;
  1315.     if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
  1316.         syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
  1317. #endif
  1318. #ifdef SO_SNDBUF
  1319.     on = 65536;
  1320.     if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
  1321.         syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
  1322. #endif
  1323.  
  1324.     return (fdopen(s, mode));
  1325. bad:
  1326.     /* Return the real value of errno (close may change it) */
  1327.     t = errno;
  1328.     (void) seteuid((uid_t)pw->pw_uid);
  1329.     (void) close(s);
  1330.     errno = t;
  1331.     return (NULL);
  1332. }
  1333.  
  1334. static FILE *
  1335. dataconn(name, size, mode)
  1336.     char *name;
  1337.     off_t size;
  1338.     char *mode;
  1339. {
  1340.     char sizebuf[32];
  1341.     FILE *file;
  1342.     int retry = 0, tos;
  1343.  
  1344.     file_size = size;
  1345.     byte_count = 0;
  1346.     if (size != (off_t) -1)
  1347.         (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size);
  1348.     else
  1349.         *sizebuf = '\0';
  1350.     if (pdata >= 0) {
  1351.         struct sockaddr_in from;
  1352.         int s, fromlen = sizeof(from);
  1353.         struct timeval timeout;
  1354.         fd_set set;
  1355.  
  1356.         FD_ZERO(&set);
  1357.         FD_SET(pdata, &set);
  1358.  
  1359.         timeout.tv_usec = 0;
  1360.         timeout.tv_sec = 120;
  1361.  
  1362.         if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
  1363.             (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
  1364.             reply(425, "Can't open data connection.");
  1365.             (void) close(pdata);
  1366.             pdata = -1;
  1367.             return (NULL);
  1368.         }
  1369.         (void) close(pdata);
  1370.         pdata = s;
  1371. #ifdef IP_TOS
  1372.         tos = IPTOS_THROUGHPUT;
  1373.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
  1374.             sizeof(int));
  1375. #endif
  1376.         reply(150, "Opening %s mode data connection for '%s'%s.",
  1377.              type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1378.         return (fdopen(pdata, mode));
  1379.     }
  1380.     if (data >= 0) {
  1381.         reply(125, "Using existing data connection for '%s'%s.",
  1382.             name, sizebuf);
  1383.         usedefault = 1;
  1384.         return (fdopen(data, mode));
  1385.     }
  1386.     if (usedefault)
  1387.         data_dest = his_addr;
  1388.     usedefault = 1;
  1389.     file = getdatasock(mode);
  1390.     if (file == NULL) {
  1391.         reply(425, "Can't create data socket (%s,%d): %s.",
  1392.             inet_ntoa(data_source.sin_addr),
  1393.             ntohs(data_source.sin_port), strerror(errno));
  1394.         return (NULL);
  1395.     }
  1396.     data = fileno(file);
  1397.     while (connect(data, (struct sockaddr *)&data_dest,
  1398.         sizeof(data_dest)) < 0) {
  1399.         if (errno == EADDRINUSE && retry < swaitmax) {
  1400.             sleep((unsigned) swaitint);
  1401.             retry += swaitint;
  1402.             continue;
  1403.         }
  1404.         perror_reply(425, "Can't build data connection");
  1405.         (void) fclose(file);
  1406.         data = -1;
  1407.         return (NULL);
  1408.     }
  1409.     reply(150, "Opening %s mode data connection for '%s'%s.",
  1410.          type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1411.     return (file);
  1412. }
  1413.  
  1414. /*
  1415.  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
  1416.  * encapsulation of the data subject to Mode, Structure, and Type.
  1417.  *
  1418.  * NB: Form isn't handled.
  1419.  */
  1420. static void
  1421. send_data(instr, outstr, blksize, filesize, isreg)
  1422.     FILE *instr, *outstr;
  1423.     off_t blksize;
  1424.     off_t filesize;
  1425.     int isreg;
  1426. {
  1427.     int c, cnt, filefd, netfd;
  1428.     char *buf, *bp;
  1429.     size_t len;
  1430.  
  1431.     transflag++;
  1432.     if (setjmp(urgcatch)) {
  1433.         transflag = 0;
  1434.         return;
  1435.     }
  1436.     switch (type) {
  1437.  
  1438.     case TYPE_A:
  1439.         while ((c = getc(instr)) != EOF) {
  1440.             byte_count++;
  1441.             if (c == '\n') {
  1442.                 if (ferror(outstr))
  1443.                     goto data_err;
  1444.                 (void) putc('\r', outstr);
  1445.             }
  1446.             (void) putc(c, outstr);
  1447.         }
  1448.         fflush(outstr);
  1449.         transflag = 0;
  1450.         if (ferror(instr))
  1451.             goto file_err;
  1452.         if (ferror(outstr))
  1453.             goto data_err;
  1454.         reply(226, "Transfer complete.");
  1455.         return;
  1456.  
  1457.     case TYPE_I:
  1458.     case TYPE_L:
  1459.         /*
  1460.          * isreg is only set if we are not doing restart and we
  1461.          * are sending a regular file
  1462.          */
  1463.         netfd = fileno(outstr);
  1464.         filefd = fileno(instr);
  1465.  
  1466.         if (isreg && filesize < (off_t)16 * 1024 * 1024) {
  1467.             buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
  1468.                    (off_t)0);
  1469.             if (buf == MAP_FAILED) {
  1470.                 syslog(LOG_WARNING, "mmap(%lu): %m",
  1471.                        (unsigned long)filesize);
  1472.                 goto oldway;
  1473.             }
  1474.             bp = buf;
  1475.             len = filesize;
  1476.             do {
  1477.                 cnt = write(netfd, bp, len);
  1478.                 len -= cnt;
  1479.                 bp += cnt;
  1480.                 if (cnt > 0) byte_count += cnt;
  1481.             } while(cnt > 0 && len > 0);
  1482.  
  1483.             transflag = 0;
  1484.             munmap(buf, (size_t)filesize);
  1485.             if (cnt < 0)
  1486.                 goto data_err;
  1487.             reply(226, "Transfer complete.");
  1488.             return;
  1489.         }
  1490.  
  1491. oldway:
  1492.         if ((buf = malloc((u_int)blksize)) == NULL) {
  1493.             transflag = 0;
  1494.             perror_reply(451, "Local resource failure: malloc");
  1495.             return;
  1496.         }
  1497.  
  1498.         while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
  1499.             write(netfd, buf, cnt) == cnt)
  1500.             byte_count += cnt;
  1501.         transflag = 0;
  1502.         (void)free(buf);
  1503.         if (cnt != 0) {
  1504.             if (cnt < 0)
  1505.                 goto file_err;
  1506.             goto data_err;
  1507.         }
  1508.         reply(226, "Transfer complete.");
  1509.         return;
  1510.     default:
  1511.         transflag = 0;
  1512.         reply(550, "Unimplemented TYPE %d in send_data", type);
  1513.         return;
  1514.     }
  1515.  
  1516. data_err:
  1517.     transflag = 0;
  1518.     perror_reply(426, "Data connection");
  1519.     return;
  1520.  
  1521. file_err:
  1522.     transflag = 0;
  1523.     perror_reply(551, "Error on input file");
  1524. }
  1525.  
  1526. /*
  1527.  * Transfer data from peer to "outstr" using the appropriate encapulation of
  1528.  * the data subject to Mode, Structure, and Type.
  1529.  *
  1530.  * N.B.: Form isn't handled.
  1531.  */
  1532. static int
  1533. receive_data(instr, outstr)
  1534.     FILE *instr, *outstr;
  1535. {
  1536.     int c;
  1537.     int cnt, bare_lfs;
  1538.     char buf[BUFSIZ];
  1539.  
  1540.     transflag++;
  1541.     if (setjmp(urgcatch)) {
  1542.         transflag = 0;
  1543.         return (-1);
  1544.     }
  1545.  
  1546.     bare_lfs = 0;
  1547.  
  1548.     switch (type) {
  1549.  
  1550.     case TYPE_I:
  1551.     case TYPE_L:
  1552.         while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
  1553.             if (write(fileno(outstr), buf, cnt) != cnt)
  1554.                 goto file_err;
  1555.             byte_count += cnt;
  1556.         }
  1557.         if (cnt < 0)
  1558.             goto data_err;
  1559.         transflag = 0;
  1560.         return (0);
  1561.  
  1562.     case TYPE_E:
  1563.         reply(553, "TYPE E not implemented.");
  1564.         transflag = 0;
  1565.         return (-1);
  1566.  
  1567.     case TYPE_A:
  1568.         while ((c = getc(instr)) != EOF) {
  1569.             byte_count++;
  1570.             if (c == '\n')
  1571.                 bare_lfs++;
  1572.             while (c == '\r') {
  1573.                 if (ferror(outstr))
  1574.                     goto data_err;
  1575.                 if ((c = getc(instr)) != '\n') {
  1576.                     (void) putc ('\r', outstr);
  1577.                     if (c == '\0' || c == EOF)
  1578.                         goto contin2;
  1579.                 }
  1580.             }
  1581.             (void) putc(c, outstr);
  1582.     contin2:    ;
  1583.         }
  1584.         fflush(outstr);
  1585.         if (ferror(instr))
  1586.             goto data_err;
  1587.         if (ferror(outstr))
  1588.             goto file_err;
  1589.         transflag = 0;
  1590.         if (bare_lfs) {
  1591.             lreply(226,
  1592.         "WARNING! %d bare linefeeds received in ASCII mode",
  1593.                 bare_lfs);
  1594.         (void)printf("   File may not have transferred correctly.\r\n");
  1595.         }
  1596.         return (0);
  1597.     default:
  1598.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  1599.         transflag = 0;
  1600.         return (-1);
  1601.     }
  1602.  
  1603. data_err:
  1604.     transflag = 0;
  1605.     perror_reply(426, "Data Connection");
  1606.     return (-1);
  1607.  
  1608. file_err:
  1609.     transflag = 0;
  1610.     perror_reply(452, "Error writing file");
  1611.     return (-1);
  1612. }
  1613.  
  1614. void
  1615. statfilecmd(filename)
  1616.     char *filename;
  1617. {
  1618.     FILE *fin;
  1619.     int c;
  1620.     char line[LINE_MAX];
  1621.  
  1622.     (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename);
  1623.     fin = ftpd_popen(line, "r");
  1624.     lreply(211, "status of %s:", filename);
  1625.     while ((c = getc(fin)) != EOF) {
  1626.         if (c == '\n') {
  1627.             if (ferror(stdout)){
  1628.                 perror_reply(421, "control connection");
  1629.                 (void) ftpd_pclose(fin);
  1630.                 dologout(1);
  1631.                 /* NOTREACHED */
  1632.             }
  1633.             if (ferror(fin)) {
  1634.                 perror_reply(551, filename);
  1635.                 (void) ftpd_pclose(fin);
  1636.                 return;
  1637.             }
  1638.             (void) putc('\r', stdout);
  1639.         }
  1640.         (void) putc(c, stdout);
  1641.     }
  1642.     (void) ftpd_pclose(fin);
  1643.     reply(211, "End of Status");
  1644. }
  1645.  
  1646. void
  1647. statcmd()
  1648. {
  1649.     struct sockaddr_in *sin;
  1650.     u_char *a, *p;
  1651.  
  1652.     lreply(211, "%s FTP server status:", hostname, version);
  1653.     printf("     %s\r\n", version);
  1654.     printf("     Connected to %s", remotehost);
  1655.     if (!isdigit(remotehost[0]))
  1656.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  1657.     printf("\r\n");
  1658.     if (logged_in) {
  1659.         if (guest)
  1660.             printf("     Logged in anonymously\r\n");
  1661.         else
  1662.             printf("     Logged in as %s\r\n", pw->pw_name);
  1663.     } else if (askpasswd)
  1664.         printf("     Waiting for password\r\n");
  1665.     else
  1666.         printf("     Waiting for user name\r\n");
  1667.     printf("     TYPE: %s", typenames[type]);
  1668.     if (type == TYPE_A || type == TYPE_E)
  1669.         printf(", FORM: %s", formnames[form]);
  1670.     if (type == TYPE_L)
  1671. #if NBBY == 8
  1672.         printf(" %d", NBBY);
  1673. #else
  1674.         printf(" %d", bytesize);    /* need definition! */
  1675. #endif
  1676.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  1677.         strunames[stru], modenames[mode]);
  1678.     if (data != -1)
  1679.         printf("     Data connection open\r\n");
  1680.     else if (pdata != -1) {
  1681.         printf("     in Passive mode");
  1682.         sin = &pasv_addr;
  1683.         goto printaddr;
  1684.     } else if (usedefault == 0) {
  1685.         printf("     PORT");
  1686.         sin = &data_dest;
  1687. printaddr:
  1688.         a = (u_char *) &sin->sin_addr;
  1689.         p = (u_char *) &sin->sin_port;
  1690. #define UC(b) (((int) b) & 0xff)
  1691.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  1692.             UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1693. #undef UC
  1694.     } else
  1695.         printf("     No data connection\r\n");
  1696.     reply(211, "End of status");
  1697. }
  1698.  
  1699. void
  1700. fatal(s)
  1701.     char *s;
  1702. {
  1703.  
  1704.     reply(451, "Error in server: %s\n", s);
  1705.     reply(221, "Closing connection due to server error.");
  1706.     dologout(0);
  1707.     /* NOTREACHED */
  1708. }
  1709.  
  1710. void
  1711. #if __STDC__
  1712. reply(int n, const char *fmt, ...)
  1713. #else
  1714. reply(n, fmt, va_alist)
  1715.     int n;
  1716.     char *fmt;
  1717.         va_dcl
  1718. #endif
  1719. {
  1720.     va_list ap;
  1721. #if __STDC__
  1722.     va_start(ap, fmt);
  1723. #else
  1724.     va_start(ap);
  1725. #endif
  1726.     (void)printf("%d ", n);
  1727.     (void)vprintf(fmt, ap);
  1728.     (void)printf("\r\n");
  1729.     (void)fflush(stdout);
  1730.     if (debug) {
  1731.         syslog(LOG_DEBUG, "<--- %d ", n);
  1732.         vsyslog(LOG_DEBUG, fmt, ap);
  1733.     }
  1734. }
  1735.  
  1736. void
  1737. #if __STDC__
  1738. lreply(int n, const char *fmt, ...)
  1739. #else
  1740. lreply(n, fmt, va_alist)
  1741.     int n;
  1742.     char *fmt;
  1743.         va_dcl
  1744. #endif
  1745. {
  1746.     va_list ap;
  1747. #if __STDC__
  1748.     va_start(ap, fmt);
  1749. #else
  1750.     va_start(ap);
  1751. #endif
  1752.     (void)printf("%d- ", n);
  1753.     (void)vprintf(fmt, ap);
  1754.     (void)printf("\r\n");
  1755.     (void)fflush(stdout);
  1756.     if (debug) {
  1757.         syslog(LOG_DEBUG, "<--- %d- ", n);
  1758.         vsyslog(LOG_DEBUG, fmt, ap);
  1759.     }
  1760. }
  1761.  
  1762. static void
  1763. ack(s)
  1764.     char *s;
  1765. {
  1766.  
  1767.     reply(250, "%s command successful.", s);
  1768. }
  1769.  
  1770. void
  1771. nack(s)
  1772.     char *s;
  1773. {
  1774.  
  1775.     reply(502, "%s command not implemented.", s);
  1776. }
  1777.  
  1778. /* ARGSUSED */
  1779. void
  1780. yyerror(s)
  1781.     char *s;
  1782. {
  1783.     char *cp;
  1784.  
  1785.     if ((cp = strchr(cbuf,'\n')))
  1786.         *cp = '\0';
  1787.     reply(500, "'%s': command not understood.", cbuf);
  1788. }
  1789.  
  1790. void
  1791. delete(name)
  1792.     char *name;
  1793. {
  1794.     struct stat st;
  1795.  
  1796.     LOGCMD("delete", name);
  1797.     if (stat(name, &st) < 0) {
  1798.         perror_reply(550, name);
  1799.         return;
  1800.     }
  1801.     if ((st.st_mode&S_IFMT) == S_IFDIR) {
  1802.         if (rmdir(name) < 0) {
  1803.             perror_reply(550, name);
  1804.             return;
  1805.         }
  1806.         goto done;
  1807.     }
  1808.     if (unlink(name) < 0) {
  1809.         perror_reply(550, name);
  1810.         return;
  1811.     }
  1812. done:
  1813.     ack("DELE");
  1814. }
  1815.  
  1816. void
  1817. cwd(path)
  1818.     char *path;
  1819. {
  1820.  
  1821.     if (chdir(path) < 0)
  1822.         perror_reply(550, path);
  1823.     else
  1824.         ack("CWD");
  1825. }
  1826.  
  1827. void
  1828. makedir(name)
  1829.     char *name;
  1830. {
  1831.  
  1832.     LOGCMD("mkdir", name);
  1833.     if (mkdir(name, 0777) < 0)
  1834.         perror_reply(550, name);
  1835.     else
  1836.         reply(257, "MKD command successful.");
  1837. }
  1838.  
  1839. void
  1840. removedir(name)
  1841.     char *name;
  1842. {
  1843.  
  1844.     LOGCMD("rmdir", name);
  1845.     if (rmdir(name) < 0)
  1846.         perror_reply(550, name);
  1847.     else
  1848.         ack("RMD");
  1849. }
  1850.  
  1851. void
  1852. pwd()
  1853. {
  1854.     char path[MAXPATHLEN + 1];
  1855.  
  1856.     if (getwd(path) == (char *)NULL)
  1857.         reply(550, "%s.", path);
  1858.     else
  1859.         reply(257, "\"%s\" is current directory.", path);
  1860. }
  1861.  
  1862. char *
  1863. renamefrom(name)
  1864.     char *name;
  1865. {
  1866.     struct stat st;
  1867.  
  1868.     if (stat(name, &st) < 0) {
  1869.         perror_reply(550, name);
  1870.         return ((char *)0);
  1871.     }
  1872.     reply(350, "File exists, ready for destination name");
  1873.     return (name);
  1874. }
  1875.  
  1876. void
  1877. renamecmd(from, to)
  1878.     char *from, *to;
  1879. {
  1880.     struct stat st;
  1881.  
  1882.     LOGCMD2("rename", from, to);
  1883.  
  1884.     if (guest && (stat(to, &st) == 0)) {
  1885.         reply(550, "%s: permission denied", to);
  1886.         return;
  1887.     }
  1888.  
  1889.     if (rename(from, to) < 0)
  1890.         perror_reply(550, "rename");
  1891.     else
  1892.         ack("RNTO");
  1893. }
  1894.  
  1895. static void
  1896. dolog(sin)
  1897.     struct sockaddr_in *sin;
  1898. {
  1899.     struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
  1900.         sizeof(struct in_addr), AF_INET);
  1901.  
  1902.     if (hp)
  1903.         (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
  1904.     else
  1905.         (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
  1906.             sizeof(remotehost));
  1907. #ifdef SETPROCTITLE
  1908. #ifdef VIRTUAL_HOSTING
  1909.     if (thishost != firsthost)
  1910.         snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
  1911.              remotehost, hostname);
  1912.     else
  1913. #endif
  1914.         snprintf(proctitle, sizeof(proctitle), "%s: connected",
  1915.              remotehost);
  1916.     setproctitle("%s", proctitle);
  1917. #endif /* SETPROCTITLE */
  1918.  
  1919.     if (logging) {
  1920. #ifdef VIRTUAL_HOSTING
  1921.         if (thishost != firsthost)
  1922.             syslog(LOG_INFO, "connection from %s (to %s)",
  1923.                    remotehost, hostname);
  1924.         else
  1925. #endif
  1926.             syslog(LOG_INFO, "connection from %s (%s)", remotehost,
  1927.                 inet_ntoa(sin->sin_addr));
  1928.     }
  1929. }
  1930.  
  1931. /*
  1932.  * Record logout in wtmp file
  1933.  * and exit with supplied status.
  1934.  */
  1935. void
  1936. dologout(status)
  1937.     int status;
  1938. {
  1939.     /*
  1940.      * Prevent reception of SIGURG from resulting in a resumption
  1941.      * back to the main program loop.
  1942.      */
  1943.     transflag = 0;
  1944.  
  1945.     if (logged_in) {
  1946.         (void) seteuid((uid_t)0);
  1947.         ftpd_logwtmp(ttyline, "", "");
  1948. #if defined(KERBEROS)
  1949.         if (!notickets && krbtkfile_env)
  1950.             unlink(krbtkfile_env);
  1951. #endif
  1952.     }
  1953.     /* beware of flushing buffers after a SIGPIPE */
  1954.     _exit(status);
  1955. }
  1956.  
  1957. static void
  1958. myoob(signo)
  1959.     int signo;
  1960. {
  1961.     char *cp;
  1962.  
  1963.     /* only process if transfer occurring */
  1964.     if (!transflag)
  1965.         return;
  1966.     cp = tmpline;
  1967.     if (getline(cp, 7, stdin) == NULL) {
  1968.         reply(221, "You could at least say goodbye.");
  1969.         dologout(0);
  1970.     }
  1971.     upper(cp);
  1972.     if (strcmp(cp, "ABOR\r\n") == 0) {
  1973.         tmpline[0] = '\0';
  1974.         reply(426, "Transfer aborted. Data connection closed.");
  1975.         reply(226, "Abort successful");
  1976.         longjmp(urgcatch, 1);
  1977.     }
  1978.     if (strcmp(cp, "STAT\r\n") == 0) {
  1979.         if (file_size != (off_t) -1)
  1980.             reply(213, "Status: %qd of %qd bytes transferred",
  1981.                 byte_count, file_size);
  1982.         else
  1983.             reply(213, "Status: %qd bytes transferred", byte_count);
  1984.     }
  1985. }
  1986.  
  1987. /*
  1988.  * Note: a response of 425 is not mentioned as a possible response to
  1989.  *    the PASV command in RFC959. However, it has been blessed as
  1990.  *    a legitimate response by Jon Postel in a telephone conversation
  1991.  *    with Rick Adams on 25 Jan 89.
  1992.  */
  1993. void
  1994. passive()
  1995. {
  1996.     int len;
  1997.     char *p, *a;
  1998.  
  1999.     if (pdata >= 0)        /* close old port if one set */
  2000.         close(pdata);
  2001.  
  2002.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  2003.     if (pdata < 0) {
  2004.         perror_reply(425, "Can't open passive connection");
  2005.         return;
  2006.     }
  2007.  
  2008.     (void) seteuid((uid_t)0);
  2009.  
  2010. #ifdef IP_PORTRANGE
  2011.     {
  2012.         int on = restricted_data_ports ? IP_PORTRANGE_HIGH
  2013.                        : IP_PORTRANGE_DEFAULT;
  2014.  
  2015.         if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
  2016.                 (char *)&on, sizeof(on)) < 0)
  2017.             goto pasv_error;
  2018.     }
  2019. #endif
  2020.  
  2021.     pasv_addr = ctrl_addr;
  2022.     pasv_addr.sin_port = 0;
  2023.     if (bind(pdata, (struct sockaddr *)&pasv_addr,
  2024.          sizeof(pasv_addr)) < 0)
  2025.         goto pasv_error;
  2026.  
  2027.     (void) seteuid((uid_t)pw->pw_uid);
  2028.  
  2029.     len = sizeof(pasv_addr);
  2030.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  2031.         goto pasv_error;
  2032.     if (listen(pdata, 1) < 0)
  2033.         goto pasv_error;
  2034.     a = (char *) &pasv_addr.sin_addr;
  2035.     p = (char *) &pasv_addr.sin_port;
  2036.  
  2037. #define UC(b) (((int) b) & 0xff)
  2038.  
  2039.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  2040.         UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2041.     return;
  2042.  
  2043. pasv_error:
  2044.     (void) seteuid((uid_t)pw->pw_uid);
  2045.     (void) close(pdata);
  2046.     pdata = -1;
  2047.     perror_reply(425, "Can't open passive connection");
  2048.     return;
  2049. }
  2050.  
  2051. /*
  2052.  * Generate unique name for file with basename "local".
  2053.  * The file named "local" is already known to exist.
  2054.  * Generates failure reply on error.
  2055.  */
  2056. static char *
  2057. gunique(local)
  2058.     char *local;
  2059. {
  2060.     static char new[MAXPATHLEN];
  2061.     struct stat st;
  2062.     int count;
  2063.     char *cp;
  2064.  
  2065.     cp = strrchr(local, '/');
  2066.     if (cp)
  2067.         *cp = '\0';
  2068.     if (stat(cp ? local : ".", &st) < 0) {
  2069.         perror_reply(553, cp ? local : ".");
  2070.         return ((char *) 0);
  2071.     }
  2072.     if (cp)
  2073.         *cp = '/';
  2074.     /* -4 is for the .nn<null> we put on the end below */
  2075.     (void) snprintf(new, sizeof(new) - 4, "%s", local);
  2076.     cp = new + strlen(new);
  2077.     *cp++ = '.';
  2078.     for (count = 1; count < 100; count++) {
  2079.         (void)sprintf(cp, "%d", count);
  2080.         if (stat(new, &st) < 0)
  2081.             return (new);
  2082.     }
  2083.     reply(452, "Unique file name cannot be created.");
  2084.     return (NULL);
  2085. }
  2086.  
  2087. /*
  2088.  * Format and send reply containing system error number.
  2089.  */
  2090. void
  2091. perror_reply(code, string)
  2092.     int code;
  2093.     char *string;
  2094. {
  2095.  
  2096.     reply(code, "%s: %s.", string, strerror(errno));
  2097. }
  2098.  
  2099. static char *onefile[] = {
  2100.     "",
  2101.     0
  2102. };
  2103.  
  2104. void
  2105. send_file_list(whichf)
  2106.     char *whichf;
  2107. {
  2108.     struct stat st;
  2109.     DIR *dirp = NULL;
  2110.     struct dirent *dir;
  2111.     FILE *dout = NULL;
  2112.     char **dirlist, *dirname;
  2113.     int simple = 0;
  2114.     int freeglob = 0;
  2115.     glob_t gl;
  2116.  
  2117.     if (strpbrk(whichf, "~{[*?") != NULL) {
  2118.         int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
  2119.  
  2120.         memset(&gl, 0, sizeof(gl));
  2121.         freeglob = 1;
  2122.         if (glob(whichf, flags, 0, &gl)) {
  2123.             reply(550, "not found");
  2124.             goto out;
  2125.         } else if (gl.gl_pathc == 0) {
  2126.             errno = ENOENT;
  2127.             perror_reply(550, whichf);
  2128.             goto out;
  2129.         }
  2130.         dirlist = gl.gl_pathv;
  2131.     } else {
  2132.         onefile[0] = whichf;
  2133.         dirlist = onefile;
  2134.         simple = 1;
  2135.     }
  2136.  
  2137.     if (setjmp(urgcatch)) {
  2138.         transflag = 0;
  2139.         goto out;
  2140.     }
  2141.     while ((dirname = *dirlist++)) {
  2142.         if (stat(dirname, &st) < 0) {
  2143.             /*
  2144.              * If user typed "ls -l", etc, and the client
  2145.              * used NLST, do what the user meant.
  2146.              */
  2147.             if (dirname[0] == '-' && *dirlist == NULL &&
  2148.                 transflag == 0) {
  2149.                 retrieve(_PATH_LS " %s", dirname);
  2150.                 goto out;
  2151.             }
  2152.             perror_reply(550, whichf);
  2153.             if (dout != NULL) {
  2154.                 (void) fclose(dout);
  2155.                 transflag = 0;
  2156.                 data = -1;
  2157.                 pdata = -1;
  2158.             }
  2159.             goto out;
  2160.         }
  2161.  
  2162.         if (S_ISREG(st.st_mode)) {
  2163.             if (dout == NULL) {
  2164.                 dout = dataconn("file list", (off_t)-1, "w");
  2165.                 if (dout == NULL)
  2166.                     goto out;
  2167.                 transflag++;
  2168.             }
  2169.             fprintf(dout, "%s%s\n", dirname,
  2170.                 type == TYPE_A ? "\r" : "");
  2171.             byte_count += strlen(dirname) + 1;
  2172.             continue;
  2173.         } else if (!S_ISDIR(st.st_mode))
  2174.             continue;
  2175.  
  2176.         if ((dirp = opendir(dirname)) == NULL)
  2177.             continue;
  2178.  
  2179.         while ((dir = readdir(dirp)) != NULL) {
  2180.             char nbuf[MAXPATHLEN];
  2181.  
  2182.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  2183.                 continue;
  2184.             if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
  2185.                 dir->d_namlen == 2)
  2186.                 continue;
  2187.  
  2188.             snprintf(nbuf, sizeof(nbuf), 
  2189.                 "%s/%s", dirname, dir->d_name);
  2190.  
  2191.             /*
  2192.              * We have to do a stat to insure it's
  2193.              * not a directory or special file.
  2194.              */
  2195.             if (simple || (stat(nbuf, &st) == 0 &&
  2196.                 S_ISREG(st.st_mode))) {
  2197.                 if (dout == NULL) {
  2198.                     dout = dataconn("file list", (off_t)-1,
  2199.                         "w");
  2200.                     if (dout == NULL)
  2201.                         goto out;
  2202.                     transflag++;
  2203.                 }
  2204.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  2205.                     fprintf(dout, "%s%s\n", &nbuf[2],
  2206.                         type == TYPE_A ? "\r" : "");
  2207.                 else
  2208.                     fprintf(dout, "%s%s\n", nbuf,
  2209.                         type == TYPE_A ? "\r" : "");
  2210.                 byte_count += strlen(nbuf) + 1;
  2211.             }
  2212.         }
  2213.         (void) closedir(dirp);
  2214.     }
  2215.  
  2216.     if (dout == NULL)
  2217.         reply(550, "No files found.");
  2218.     else if (ferror(dout) != 0)
  2219.         perror_reply(550, "Data connection");
  2220.     else
  2221.         reply(226, "Transfer complete.");
  2222.  
  2223.     transflag = 0;
  2224.     if (dout != NULL)
  2225.         (void) fclose(dout);
  2226.     data = -1;
  2227.     pdata = -1;
  2228. out:
  2229.     if (freeglob) {
  2230.         freeglob = 0;
  2231.         globfree(&gl);
  2232.     }
  2233. }
  2234.  
  2235. void
  2236. reapchild(signo)
  2237.     int signo;
  2238. {
  2239.     while (wait3(NULL, WNOHANG, NULL) > 0);
  2240. }
  2241.  
  2242. #ifdef OLD_SETPROCTITLE
  2243. /*
  2244.  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
  2245.  * Warning, since this is usually started from inetd.conf, it often doesn't
  2246.  * have much of an environment or arglist to overwrite.
  2247.  */
  2248. void
  2249. #if __STDC__
  2250. setproctitle(const char *fmt, ...)
  2251. #else
  2252. setproctitle(fmt, va_alist)
  2253.     char *fmt;
  2254.         va_dcl
  2255. #endif
  2256. {
  2257.     int i;
  2258.     va_list ap;
  2259.     char *p, *bp, ch;
  2260.     char buf[LINE_MAX];
  2261.  
  2262. #if __STDC__
  2263.     va_start(ap, fmt);
  2264. #else
  2265.     va_start(ap);
  2266. #endif
  2267.     (void)vsnprintf(buf, sizeof(buf), fmt, ap);
  2268.  
  2269.     /* make ps print our process name */
  2270.     p = Argv[0];
  2271.     *p++ = '-';
  2272.  
  2273.     i = strlen(buf);
  2274.     if (i > LastArgv - p - 2) {
  2275.         i = LastArgv - p - 2;
  2276.         buf[i] = '\0';
  2277.     }
  2278.     bp = buf;
  2279.     while (ch = *bp++)
  2280.         if (ch != '\n' && ch != '\r')
  2281.             *p++ = ch;
  2282.     while (p < LastArgv)
  2283.         *p++ = ' ';
  2284. }
  2285. #endif /* OLD_SETPROCTITLE */
  2286.  
  2287. static void
  2288. logxfer(name, size, start)
  2289.     char *name;
  2290.     long size;
  2291.     long start;
  2292. {
  2293.     char buf[1024];
  2294.     char path[MAXPATHLEN + 1];
  2295.     time_t now;
  2296.  
  2297.     if (statfd >= 0 && getwd(path) != NULL) {
  2298.         time(&now);
  2299.         snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n",
  2300.             ctime(&now)+4, ident, remotehost,
  2301.             path, name, size, now - start + (now == start));
  2302.         write(statfd, buf, strlen(buf));
  2303.     }
  2304. }
  2305.